package com.cyf.app.service.impl;

import com.cyf.activemq.network.bean.MqBookingReq;
import com.cyf.activemq.network.bean.MqBusinessOpt;
import com.cyf.activemq.service.SendMsgService;
import com.cyf.app.network.bean.AppBusinessRsp;
import com.cyf.app.network.bean.booking.*;
import com.cyf.app.service.AppBookingService;
import com.cyf.service.CheckParam;
import com.cyf.db.bean.CurLogin;
import com.cyf.db.bean.*;
import com.cyf.db.mapper.*;
import com.cyf.service.BookingService;
import com.cyf.service.CommonService;
import com.cyf.service.bean.CustomException;
import com.cyf.util.DateUtil;
import com.cyf.util.ObjectMapperUtils;
import com.cyf.util.ParkingUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

/**
 * app车位预约接口实现类
 * Created by cage on 2017/4/7.
 */
@Service
public class AppBookingServiceImpl implements AppBookingService {

    private static Logger logger = LoggerFactory.getLogger(AppBookingServiceImpl.class);

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ParkingMapper parkingMapper;
    @Autowired
    private BookingInfoMapper bookingInfoMapper;
    @Autowired
    private ParkingLockInfoMapper parkingLockInfoMapper;
    @Autowired
    private FeeGroupMapper feeGroupMapper;
    @Autowired
    private CurLoginMapper curLoginMapper;

    @Autowired
    private SendMsgService sendMsgService;
    @Autowired
    private CheckParam checkParam;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BookingService bookingService;

    @Override
    public AppGetParkingsRsp getParkings(AppGetParkingsReq req) {
        AppGetParkingsRsp rsp = new AppGetParkingsRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {
            List<AppGetParkingsItem> list = new ArrayList<>();
            // 获取支持车位预约的车场
            List<Parking> parkings = null;
            // TODO: 2018/8/13
//            if (req.getLongitude() == 0.00 || req.getLatitude() == 0.00) {
//                parkings = parkingMapper.getParkingsByUseBooking(Parking.ENABLE_BOOKING);
//            } else {
//                parkings = parkingMapper.getParkingsByUseBookingWithRange(Parking.ENABLE_BOOKING, req.getLongitude(), req.getLatitude());
//            }
            if (parkings != null && parkings.size() > 0) {
                List<Integer> curLoginParkingList = curLoginMapper.getCurLogins();
                if (curLoginParkingList == null) {
                    curLoginParkingList = new ArrayList<>();
                }
                for (Parking parking : parkings) {
                    // 车场不支持网络支付，跳过
                    if (!commonService.checkSupportOnlinePay(parking.getId())) {
                        continue;
                    }
                    FeeGroup feeGroup = feeGroupMapper.getBookingFeeGroup(parking.getId());
                    if (feeGroup == null) {
                        logger.error("车场({})支持车位预约，没有计费规则!", parking.getId());
                        continue;
                    }
                    String fee = ParkingUtil.getFee(feeGroup.getFreeAmount());
                    int count = parkingLockInfoMapper.getCountByParkingId(parking.getId());
                    AppGetParkingsItem item = new AppGetParkingsItem();
                    item.setParkingId(parking.getId());
                    item.setParkingName(ParkingUtil.getParkingName(parking.getName()));
                    item.setAddress(parking.getAddress());
                    item.setLongitude(parking.getLongitude());
                    item.setLatitude(parking.getLatitude());
                    item.setCarport(count);
                    if (feeGroup.getQrCodeType() == FeeGroup.BOOKING_TYPE_HOURS) {
                        item.setFee(fee + "元/半小时");
                    } else if (feeGroup.getQrCodeType() == FeeGroup.BOOKING_TYPE_ONCE) {
                        item.setFee(fee + "元/次");
                    } else {
                        logger.error("车位预约计费规则类型()错误!", feeGroup.getQrCodeType());
                        continue;
                    }

                    item.setShowFee("￥" + fee);
                    // 1绿色 2灰色(离线) 3红色(车位0)
                    if (curLoginParkingList.contains(parking.getId())) {
                        item.setColor(count > 0 ? 1 : 3);
                    } else {
                        item.setColor(2);
                    }
                    list.add(item);
                }
            }
            rsp.setParkings(list);
            rsp.setResult(AppBusinessRsp.SUCCESS);
        } catch (Exception e) {
            logger.error("获取预约车场列表异常：{}", e);
            rsp.setStrError("服务器异常");
        }
        return rsp;
    }

    @Override
    @Transactional
    public AppBookingRsp booking(AppBookingReq req) {
        AppBookingRsp rsp = new AppBookingRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {
            List<AppCar> appCars = checkParam.getAppCars(user);

            CurLogin curLogin= curLoginMapper.getByParkingId(req.getParkingId());
            if (curLogin == null) {
                rsp.setStrError("该车场暂不支持预约!");
                return rsp;
            }

            if (!commonService.checkSupportOnlinePay(req.getParkingId())) {
                rsp.setStrError("该车场暂不支持预约!");
                return rsp;
            }

            ParkingLockInfo lockInfo = parkingLockInfoMapper.getUsedByParkingId(req.getParkingId());
            if (lockInfo == null) {
                rsp.setStrError("没有车位可以预约！");
                return rsp;
            }

            FeeGroup feeGroup = feeGroupMapper.getBookingFeeGroup(req.getParkingId());
            if (feeGroup == null || feeGroup.getFreeAmount() == null) {
                logger.error("查找预约计费规则失败");
                rsp.setStrError("预约失败！");
                return rsp;
            }

            // EB不足，预约失败！
            Integer ebBalance = user.getEbBalance();
            ebBalance = ebBalance == null ? 0 : ebBalance;
            /*if (ebBalance == null || ebBalance < feeGroup.getFreeAmount()) {
                rsp.setStrError("EB不足，预约失败！");
                return rsp;
            }*/

            // 车位预约信息保存到数据库
            Date bookingTime = new Date();
            BookingInfo bookingInfo = new BookingInfo();
            bookingInfo.setAppUserId(user.getId());
            bookingInfo.setParkingId(req.getParkingId());
            bookingInfo.setCreatedTime(bookingTime);
            bookingInfo.setBookingStatus(BookingInfo.BOOKINGSTATUS_BOOKED);
            bookingInfo.setFeeType(feeGroup.getQrCodeType());   // 预约类型 1-半小时 2-次
            bookingInfo.setFee(feeGroup.getFreeAmount());
            bookingInfo.setParkingLockId(lockInfo.getId());
            if (feeGroup.getQrCodeType() == FeeGroup.BOOKING_TYPE_HOURS) {
                bookingInfo.setEndTime(bookingInfo.caculateEndTimeWithHours(bookingTime, ebBalance, feeGroup.getFreeAmount()));
            } else if (feeGroup.getQrCodeType() == FeeGroup.BOOKING_TYPE_ONCE) {
                bookingInfo.setEndTime(bookingInfo.caculateEndTimeWithOnce(bookingTime, feeGroup.getFreeHours()));
            } else {
                logger.error("预约计费规则类型({})不支持！", feeGroup.getQrCodeType());
                rsp.setStrError("预约失败");
                return rsp;
            }
            bookingInfoMapper.insertBookingInfo(bookingInfo);
            // 更新地锁被预约消息
            parkingLockInfoMapper.booking(lockInfo.getId());

            rsp.setResult(AppBusinessRsp.SUCCESS);

            // TOC->TOB->PMSVR
            MqBookingReq mqBookingReq = new MqBookingReq();
            mqBookingReq.setOptid(MqBusinessOpt.BOOKING);
            mqBookingReq.setUuid(UUID.randomUUID().toString());
            mqBookingReq.setBookingId(bookingInfo.getId());
            List<String> plates = new ArrayList<>();
            for (AppCar appCar : appCars) {
                plates.add(appCar.getPlate());
            }
            mqBookingReq.setPlates(plates);
            mqBookingReq.setParkingId(req.getParkingId());
            mqBookingReq.setParkingLockId(lockInfo.getId());
            mqBookingReq.setCreatedTime(DateUtil.formatDate(bookingTime, MqBookingReq.PATTERN_CREATEDTIME));
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqBookingReq));
        } catch (CustomException e) {
            rsp.setStrError(e.getMessage());
        } catch (Exception e) {
            logger.error("车位预约异常：{}", e);
            rsp.setStrError("服务器异常！");
            // 手动回滚，controller层无需处理异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return rsp;
    }

    @Override
    public AppGetBookingInfoRsp getBookingInfo(AppGetBookingInfoReq req) {
        AppGetBookingInfoRsp rsp = new AppGetBookingInfoRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {

            List<AppGetBookingInfoItem> list = new ArrayList<>();
            List<BookingInfo> bookingInfos = bookingInfoMapper.getBooked(user.getId());

            if (bookingInfos != null && bookingInfos.size() > 0) {
                for (BookingInfo bookingInfo : bookingInfos) {
                    AppGetBookingInfoItem item = new AppGetBookingInfoItem();
                    item.setBookingTime(DateUtil.formatDate(bookingInfo.getCreatedTime(), AppGetBookingInfoItem.PATTERN_BOOKINGTIME));
                    Parking parking = parkingMapper.getParkingById(bookingInfo.getParkingId());
                    if (parking == null) {
                        continue;
                    }
                    ParkingLockInfo parkingLockInfo = parkingLockInfoMapper.getById(bookingInfo.getParkingLockId());
                    if (parkingLockInfo == null) {
                        logger.error("查询预约信息({})地锁({})失败！", bookingInfo.getId(), bookingInfo.getParkingLockId());
                        continue;
                    }
                    item.setParkingLockId(parkingLockInfo.getId());
                    item.setParkingLockName(parkingLockInfo.getName());
                    item.setParkingLockStatus(parkingLockInfo.getLockStatus());
                    item.setParkingName(ParkingUtil.getParkingName(parking.getName()));
                    item.setLongitude(parking.getLongitude());
                    item.setLatitude(parking.getLatitude());
                    item.setBookingId(bookingInfo.getId());
                    item.setMacAddress(parkingLockInfo.getMacAddress());
                    list.add(item);
                }
            }
            rsp.setInfos(list);
            rsp.setResult(AppBusinessRsp.SUCCESS);
            // 下发车场
        } catch (Exception e) {
            logger.error("获取车位预约信息列表异常：{}", e);
            rsp.setStrError("服务器异常");
        }
        return rsp;
    }

    @Override
    @Transactional
    public AppCancelBookingRsp cancelBooking(AppCancelBookingReq req) {
        AppCancelBookingRsp rsp = new AppCancelBookingRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {
            BookingInfo bookingInfo = bookingInfoMapper.getById(req.getBookingId());
            if (bookingInfo == null) {
                rsp.setStrError("查找预约信息失败！");
                return rsp;
            }
            bookingService.cacelBooking(bookingInfo, user);
            rsp.setResult(AppBusinessRsp.SUCCESS);
        } catch (Exception e) {
            logger.error("取消车位预约异常：{}", e);
            rsp.setStrError("服务器异常");
        }
        return rsp;
    }

    @Override
    public AppGetParkingLocksRsp getParkingLocks(AppGetParkingLocksReq req) {
        AppGetParkingLocksRsp rsp = new AppGetParkingLocksRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {
            BookingInfo bookingInfo = bookingInfoMapper.getById(req.getBookingId());
            if (bookingInfo == null || bookingInfo.getBookingStatus() != BookingInfo.BOOKINGSTATUS_BOOKED) {
                rsp.setStrError("查找预约信息失败！");
                return rsp;
            }
            List<AppGetParkingLocksItem> list = new ArrayList<>();
            List<ParkingLockInfo> unLockInfos = parkingLockInfoMapper.getUnLockInfos(bookingInfo.getParkingId());
            if (unLockInfos != null && unLockInfos.size() > 0) {
                for (ParkingLockInfo parkingLockInfo : unLockInfos) {
                    AppGetParkingLocksItem item = new AppGetParkingLocksItem();
                    item.setParkingLockId(parkingLockInfo.getId());
                    item.setParkingLockName(parkingLockInfo.getName());
                    item.setMacAddress(parkingLockInfo.getMacAddress());
                    list.add(item);
                }
            }
            rsp.setParkingLocks(list);
            rsp.setResult(AppBusinessRsp.SUCCESS);
        } catch (Exception e) {
            logger.error("获取地锁列表异常：{}", e);
            rsp.setStrError("服务器异常");
        }
        return rsp;
    }

    @Override
    public AppGetMacAddressRsp getMacAddress(AppGetMacAddressReq req) {
        AppGetMacAddressRsp rsp = new AppGetMacAddressRsp();
        rsp.setResult(AppBusinessRsp.FAIL);
        User user;
        try {
            user = checkParam.getAppUser(req.getToken());
        } catch (CustomException e) {
            rsp.setResult(AppBusinessRsp.TIMEOUT);
            rsp.setStrError(e.getMessage());
            return rsp;
        }
        try {
            BookingInfo bookingInfo = bookingInfoMapper.getById(req.getBookingId());
            if (bookingInfo == null) {
                rsp.setStrError("该预约订单不存在！");
                return rsp;
            }
            ParkingLockInfo parkingLockInfo = parkingLockInfoMapper.getById(bookingInfo.getParkingLockId());
            if (parkingLockInfo == null) {
                rsp.setStrError("查找地锁信息失败！");
            } else {
                rsp.setMacAddress(parkingLockInfo.getMacAddress());
                rsp.setResult(AppBusinessRsp.SUCCESS);
            }
        } catch (Exception e) {
            logger.error("降锁时获取地锁信息异常：{}", e);
            rsp.setStrError("服务器异常");
        }
        return rsp;
    }

}
